package cs294s.liveradar.service;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;

import cs294s.liveradar.R;
import cs294s.liveradar.data.Blip;
import cs294s.liveradar.data.Filter;

import edu.stanford.concierge.Concierge;

import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log;
import android.widget.Toast;


/*
 * Uses concierge to download blips and pass them to the Map and BlipList.
 */
public class FeedManager extends Observed{

	private class Mapping {
		int feedIndex;
		int blipIndex;
	}
	
	/**
	 * Holds the single instance of a that is shared by the process.
	 */
	public static final String LIVERADAR_TAG = "liveradar_blip2";
	private static FeedManager sInstance;
	private Context mContext;

	Concierge concierge;
	String username;
	String password;

	private Builder alertBox;

	
	ArrayList<Feed> feeds = new ArrayList<Feed>();
	Set<String> ids_added = new HashSet<String>();
	
	ArrayList<Mapping> map = new ArrayList<Mapping>();

	public static FeedManager getInstance(Context c) {
		if (sInstance == null) {
			sInstance = new FeedManager(c);
		}
		return sInstance;
	}


	private FeedManager(Context c) {
		mContext = c;
		feeds = new ArrayList<Feed>();
		alertBox = new AlertDialog.Builder(mContext)
		.setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener() {
			public void onClick(DialogInterface dialog, int whichButton) {

			}
		});
	}

	public void readPreferences() {
		SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
		username = prefs.getString("ConciergeUsername", "");
		password = prefs.getString("ConciergePassword", "");
	}

	/* Check if logged into Concierge */
	public boolean isLoggedIn() {
		return(concierge!=null);
	}

	/*If username and password have changed, then re-login.*/
	public boolean checkLogin() {
		if(isLoggedIn() == false) {
			return loginToConcierge();
		}
		String prev_username = username;
		String prev_password = password;
		readPreferences();
		if(!prev_username.equals(username) || !prev_password.equals(password))
			return loginToConcierge();
		return true;
	}

	public void logoutOfConcierge() {
		concierge = null;
	}

	public boolean loginToConcierge() {
		if(!Util.isNetworkAvailable(mContext)) {

			Toast.makeText(mContext, "Cannot connect to Concierge. Please check internet connectivity", Toast.LENGTH_SHORT).show();
			//showAlert("Cannot connect to Concierge. Please check internet connectivity");
			return false;
		}

		readPreferences();
		if(username.equals("")) {
			showAlert("Welcome to LiveRadar. Please go to Settings and enter your Concierge username and password.");
			return false;
		} 
		Toast.makeText(mContext, "Connecting to Concierge...", Toast.LENGTH_SHORT).show();

		try {	
			//Toast.makeText(mContext, "Connecting to Concierge...", Toast.LENGTH_SHORT).show();

			concierge = new Concierge("http://colby.stanford.edu/community_vibe/concierge/rpc.php", username, password);
			Toast.makeText(mContext, "Connected to Concierge", Toast.LENGTH_SHORT).show();
			
			//showAlert("Logged in to concierge");
		} catch (Exception e) {
			Toast.makeText(mContext, "Unable to connect to Concierge", Toast.LENGTH_SHORT).show();
			//showAlert("Unable to login to Concierge with username: " + username);

			return false;
		}
		return true;
	}

	private void showAlert(String msg) {
		alertBox.setTitle("Concierge Login");
		alertBox.setMessage(msg);
		alertBox.show();
	}


	public boolean sendBlip(Blip blip) {
		if(checkLogin()) {
			blip.addTag(LIVERADAR_TAG);
			concierge.postMessage(blip.toJSON(), blip.tagsToStringArr());
			return true;
		}
		return false;
	}





	public int size() {
		return feeds.size();
	}

	public Feed get(int position) {
		return feeds.get(position);
	}

	/**
	 * Clear all downloaded content
	 */
	public void clear() {
		feeds.clear();   
		notifyObservers();
	}



	/**
	 * Add an item to and notify observers of the change.
	 * @param item The item to add
	 */
	public void addFeed(Feed f) {

		String feed_id = f.getId();
		if(!ids_added.contains(feed_id)){
			ids_added.add(feed_id);
			feeds.add(f);
			Log.d("RADAR", "ADDED feed: " + feed_id + " TOTAL SIZE: " + size());
		}
	}

	
	public void replaceFeed(Feed f) {
		Log.d("RADAR", "REPLACING FEED");
		for(int i = 0; i < feeds.size(); i++) {
			Feed curr = feeds.get(i);
			if(curr.getId().equals(f.getId())) {
				feeds.set(i, f);
				Log.d("RADAR", "FEED REPLACED");
				return;
			}
		}
		
	}
	public void updateFeeds() {
		
		Log.d("RADAR", "UPDATING FEEDS");
		for(Feed f : feeds) {
			updateFeed(f);
		}
		linearMapping();
	}
	
	public void updateFeed(Feed f) {
		if(checkLogin()) {
			mLoading = true;
			new NetworkThread(f).start();
		}
	}
	
	
	public Blip linearMappingGet(int position) {
		Mapping m = map.get(position);
		Feed f = feeds.get(m.feedIndex);
		return f.get(m.blipIndex);
	}

	private void linearMapping() {
		map.clear();
		for(int i = 0; i < feeds.size(); i++) {
			Feed f = feeds.get(i);
			for(int j = 0; j < f.size(); j ++) {
				Mapping m = new Mapping();
				m.feedIndex = i;
				m.blipIndex = j;
				map.add(m);
			}
		}
	}
	
	public int linearSize() {
		return map.size();
	}
	
	/**
	 * This thread does the actual work of downloading and parsing data.
	 *
	 */
	private class NetworkThread extends Thread {
		private Feed feed;
		
		public NetworkThread(Feed feed) {
			this.feed = feed;
		}

		@Override
		public void run() {
			downloadBlips();
		}

		public void downloadBlips() {
			JSONArray ja = Concierge.getTaglistStream("http://colby.stanford.edu/community_vibe/concierge/rpc.php", feed.getTagsArr(),  Long.toString(feed.getLatestMessageId()), "10");
			if(ja == null) return;
			for(int i =ja.size() - 1; i >= 0; i--) {
				try{
					JSONObject j = (JSONObject) ja.get(i);
					long mid = (Long)j.get("mid");
					String content = (String)j.get("content");
					JSONObject blip_json = (JSONObject) JSONValue.parse(content);
					final Blip b = new Blip(blip_json);
					b.setId(mid);
					final boolean done = i == 0;
					feed.getHandler().post(new Runnable() {
						public void run() {
							sInstance.mLoading = !done;
							feed.addBlip(b);
						}
					});

				} catch (NullPointerException e) {
					Log.d("RADAR", "CAN'T READ CONCIERGE OBJECT: " + ja.toString());
				}
			}				
			feed.getHandler().post(new Runnable() {
				public void run() {
					sInstance.notifyObservers();
				}
			});

		}

	}

}
